﻿// ------------------------------------------------------------------------------------
//      Copyright (c) uhavemyword@gmail.com. All rights reserved.
//      Created by Ben at 2/20/2013 4:18:13 PM
// ------------------------------------------------------------------------------------

namespace CP.NLayer.Service.Services
{
    using CP.General;
    using CP.NLayer.Data;
    using CP.NLayer.Models.Business;
    using CP.NLayer.Models.Entities;
    using CP.NLayer.Service.Contracts;
    using Microsoft.Practices.Unity;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceModel;

    [ErrorHandlingBehavior]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class UserEditModelService : IUserEditModelService
    {
        public UserEditModel Create()
        {
            var roleService = DependencyInjection.Container.Resolve<IRoleService>();
            return new UserEditModel
            {
                User = new User() { PasswordHash = Guid.NewGuid().ToString("N") },
                RoleList = roleService.GetCheckList()
            };
        }

        public UserEditModel GetById(object id)
        {
            var worker = DependencyInjection.Container.Resolve<IUnitOfWork>();
            var user = worker.GetRepository<User>().Table.Where(x => x.Id == (string)id).Include(x => x.Roles).FirstOrDefault();
            if (user == null)
            {
                return null;
            }
            var model = new UserEditModel();
            model.User = user;
            var roleService = DependencyInjection.Container.Resolve<IRoleService>();
            model.RoleList = roleService.GetCheckList();
            model.RoleList.ToList().ForEach(x => x.Checked = model.User.Roles.Where(y => y.Name == x.Text).Count() == 1);
            return model;
        }

        public UserEditModel Insert(UserEditModel model)
        {
            var worker = DependencyInjection.Container.Resolve<IUnitOfWork>(); // use same worker for following service
            var service = DependencyInjection.Container.Resolve<IUserService>(new ParameterOverride("worker", worker));
            var roleService = DependencyInjection.Container.Resolve<IRoleService>(new ParameterOverride("worker", worker));
            if (!string.IsNullOrEmpty(model.Password))
            {
                model.User.PasswordHash = AESEncryption.Encrypt(model.Password, model.User.PasswordSalt);
            }
            var user = service.Insert(model.User);
            var roles = roleService.GetAll();
            foreach (var role in roles)
            {
                if (model.RoleList.Where(x => x.Text == role.Name && x.Checked == true).Count() == 1)
                {
                    user.Roles.Add(role);
                }
            }
            service.Update(user);
            return new UserEditModel
            {
                User = user,
                RoleList = roleService.GetCheckList() // original model.RoleList is not in the current DbContext if the model is from WCF client.
            };
        }

        public void Update(UserEditModel model)
        {
            var worker = DependencyInjection.Container.Resolve<IUnitOfWork>(); // use same worker for following service
            var service = DependencyInjection.Container.Resolve<IUserService>(new ParameterOverride("worker", worker));
            var roleService = DependencyInjection.Container.Resolve<IRoleService>(new ParameterOverride("worker", worker));

            var user = model.User;
            service.Update(user); // update fields
            // Get user again, because the previous one is not proxy type if the model is from WCF client. And eagerly load Roles.
            user = worker.GetRepository<User>().Table.Where(x => x.Id == user.Id).Include(x => x.Roles).FirstOrDefault();
            if (!string.IsNullOrEmpty(model.Password))
            {
                user.PasswordHash = AESEncryption.Encrypt(model.Password, user.PasswordSalt);
            }
            var roles = roleService.GetAll();
            foreach (var role in roles)
            {
                if (model.RoleList.Where(x => x.Text == role.Name && x.Checked == true).Count() == 1)
                {
                    if (!user.Roles.Any(x => x.Id == role.Id))
                    {
                        user.Roles.Add(role);
                    }
                }
                else
                {
                    if (user.Roles.Any(x => x.Id == role.Id))
                    {
                        user.Roles.Remove(role);
                    }
                }
            }

            service.Update(user); // update relationship
        }

        public void Delete(UserEditModel entity)
        {
            var service = DependencyInjection.Container.Resolve<IUserService>();
            service.Delete(entity.User);
        }

        public void DeleteById(object id)
        {
            var service = DependencyInjection.Container.Resolve<IUserService>();
            service.DeleteById(id);
        }
    }
}
